package com.piece.core.pay.client.impl.wxpay;

import com.piece.core.framework.exception.ErrorCode;
import com.piece.core.framework.support.response.AjaxResponse;
import com.piece.core.framework.util.object.ObjectUtil;
import com.piece.core.framework.util.string.StringUtil;
import com.piece.core.framework.util.time.DateUtil;
import com.piece.core.pay.dto.*;
import com.piece.core.pay.enums.PayChannelType;
import com.piece.core.pay.exception.PayConfigException;
import com.wechat.pay.java.core.RSAConfig;
import com.wechat.pay.java.core.exception.HttpException;
import com.wechat.pay.java.core.exception.MalformedMessageException;
import com.wechat.pay.java.core.exception.ServiceException;
import com.wechat.pay.java.core.util.IOUtil;
import com.wechat.pay.java.core.util.PemUtil;
import com.wechat.pay.java.service.payments.nativepay.NativePayService;
import com.wechat.pay.java.service.payments.nativepay.model.Amount;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayRequest;
import com.wechat.pay.java.service.payments.nativepay.model.PrepayResponse;
import com.wechat.pay.java.service.payments.nativepay.model.SceneInfo;
import com.wechat.pay.java.service.refund.RefundService;
import com.wechat.pay.java.service.weixinpayscanandride.WeixinPayScanAndRideService;
import lombok.extern.slf4j.Slf4j;

/**
 * 微信native支付实现类
 */
@Slf4j
public class WXNativePayClient extends AbstractWxPayClient {

    private NativePayService service;

    public WXNativePayClient(String channelId, WXPayClientConfig config) {
        super(channelId, PayChannelType.WX_NATIVE.getCode(), config);
    }

    @Override
    protected void doInit() {
        try {
            RSAConfig rsaConfig = new RSAConfig.Builder()
                    .merchantId(config.getMchId())
                    .privateKey(PemUtil.loadPrivateKeyFromString(IOUtil.toString(config.getPrivateKey())))
                    .merchantSerialNumber(getSerialNumber(config.getPrivateCert()))
                    .wechatPayCertificates(IOUtil.toString(config.getPrivateCert()))
                    .build();
            service = new NativePayService.Builder().config(rsaConfig).build();
            refundService = new RefundService.Builder().config(rsaConfig).build();
            rideService = new WeixinPayScanAndRideService.Builder().config(rsaConfig).build();
        } catch (Exception e) {
            throw new PayConfigException();
        }
    }

    /**
     * 下单实现接口
     */
    @Override
    public AjaxResponse doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) {
        PrepayResponse response;
        try {
            PrepayRequest request = new PrepayRequest();
            request.setOutTradeNo(reqDTO.getMerchantOrderId());
            request.setDescription(reqDTO.getBody());
            // 设置金额,单位分
            Amount amount = new Amount();
            amount.setTotal(reqDTO.getAmount().intValue());
            request.setAmount(amount);
            request.setTimeExpire(DateUtil.formatDate(reqDTO.getExpireTime(), "yyyy-MM-dd'T'HH:mm:ssXXX"));
            // 设置场景
            SceneInfo sceneInfo = new SceneInfo();
            sceneInfo.setPayerClientIp(reqDTO.getUserIp());
            request.setSceneInfo(sceneInfo);
            request.setNotifyUrl(StringUtil.isEmpty(reqDTO.getNotifyUrl()) ? config.getNotifyUrl() : reqDTO.getNotifyUrl());
            // 执行请求
            response = service.prepay(request);
        } catch (HttpException e) { // 发送HTTP请求失败
            log.error("[微信native支付失败] 原因：{}", e);
            return AjaxResponse.result(ErrorCode.HTTP, "微信支付失败");
        } catch (ServiceException e) { // 服务返回状态小于200或大于等于300，例如500
            log.error("[微信native支付失败] 原因：{}", e);
            return AjaxResponse.result(codeMapping.apply(
                    ObjectUtil.defaultIfNull(e.getErrorCode(), "CustomErrorCode"),
                    ObjectUtil.defaultIfNull(e.getErrorMessage())), null);
        } catch (MalformedMessageException e) { // 服务返回成功，返回体类型不合法，或者解析返回体失败
            log.error("[微信native支付失败] 原因：{}", e);
            return AjaxResponse.result(ErrorCode.ARGUMENT, "微信支付失败");
        }

        return AjaxResponse.result(codeMapping.apply(WXResponseMapping.CODE_SUCCESS, WXResponseMapping.MESSAGE_SUCCESS), response.getCodeUrl());
    }
}
